﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TaskHelper.cs" company="DHGMS Solutions">
//   Copyright 2004-2014 DHGMS Solutions.
//      
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//      
//   http://www.apache.org/licenses/LICENSE-2.0
//      
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
// </copyright>
// <summary>
//   Helper methods for tasks
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Dhgms.TplHelper.Helpers
{
    using System;
    using System.Diagnostics;
    using System.Threading.Tasks;
    using System.Linq;

    /// <summary>
    /// Helper methods for tasks
    /// </summary>
    public static class TaskHelper
    {
        ///// <summary>
        ///// Runs a task instantly
        ///// </summary>
        ///// <param name="task">
        ///// The task to run.
        ///// </param>
        ///// <typeparam name="TTaskClass">
        ///// The type of the task being run
        ///// </typeparam>
        ///// <typeparam name="TResultClass">
        ///// The type of the result information being returned
        ///// </typeparam>
        ///// <returns>
        ///// Job Result Information
        ///// </returns>
        //public static TResultClass Execute<TTaskClass, TResultClass>(TTaskClass task)
        //    where TResultClass : TaskResultBase, new()
        //    where TTaskClass : BaseTaskHelper<TResultClass>
        //{
        //    if (task == null)
        //    {
        //        throw new ArgumentNullException("task");
        //    }

        //    if (Debugger.IsAttached)
        //    {
        //        return task.Execute();
        //    }

        //    var t = task.Task;
        //    t.RunSynchronously();

        //    if (!task.Task.IsFaulted)
        //    {
        //        return task.Task.Result;
        //    }

        //    if (t.Exception == null)
        //    {
        //        throw new TaskCanceledException();
        //    }

        //    if (t.Exception.InnerExceptions != null && t.Exception.InnerExceptions.Count == 1)
        //    {
        //        throw t.Exception.InnerExceptions[0];
        //    }

        //    throw t.Exception;
        //}

        /// <summary>
        /// Executes a job, adds the result to the TaskResultCollection and returns the internal data. Used to streamline some
        /// common functionality.
        /// </summary>
        /// <param name="task">
        /// The task.
        /// </param>
        /// <param name="taskResultCollection">
        /// The task result collection.
        /// </param>
        /// <typeparam name="TTaskClass">
        /// Type for the task class.
        /// </typeparam>
        /// <typeparam name="TResultClass">
        /// Type for the task result.
        /// </typeparam>
        /// <typeparam name="TTaskDataType">
        /// Type for the Task Result Data Type.
        /// </typeparam>
        /// <returns>
        /// The task Result
        /// </returns>
        /*
        public static TTaskDataType GetExecutionData<TTaskClass, TResultClass, TTaskDataType>(TTaskClass task, TaskCollection taskResultCollection)
            where TResultClass : TaskResultBase, ITaskDataResult<TTaskDataType>, new()
            where TTaskClass : BaseTaskHelper<TResultClass>
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            if (taskResultCollection == null)
            {
                throw new ArgumentNullException("taskResultCollection");
            }

            var taskResult = Execute<TTaskClass, TResultClass>(task);
            taskResultCollection.TaskResults.Add(taskResult);

            return taskResult.Data;
        }
         * */

        public static void WaitWithoutThrowing(this Task task)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            InternalWaitWithoutThrowing(task);
        }

        public static void WaitWithoutThrowingUnlessDebugging(this Task task)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            if (Debugger.IsAttached)
            {
                task.Wait();
            }
            else
            {
                InternalWaitWithoutThrowing(task);
            }
        }

        private static void InternalWaitWithoutThrowing(Task task)
        {
            try
            {
                task.Wait();
            }
            catch
            {
                // ignored
            }
        }

        public static void WhenAllWithoutThrowing(Task[] tasks)
        {
            if (tasks == null)
            {
                throw new ArgumentNullException("tasks");
            }

            if (tasks.Any(x => x == null))
            {
                throw new ArgumentException("a null item exists in the collection", "tasks");
            }

            foreach (var task in tasks)
            {
                task.WaitWithoutThrowing();
            }
        }

        public static void WhenAllWithoutThrowingUnlessDebugging(Task[] tasks)
        {
            if (tasks == null)
            {
                throw new ArgumentNullException("tasks");
            }

            if (tasks.Any(x => x == null))
            {
                throw new ArgumentException("a null item exists in the collection", "tasks");
            }

            foreach (var task in tasks)
            {
                task.WaitWithoutThrowingUnlessDebugging();
            }
        }

        /*
        public static async Task<TResult> DoTask<TResult>(
            string taskDescription,
            Func<Task<TResult>> task)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            return await InternalDoTaskFunc(taskDescription, task);
        }

        public static async Task<TResult> DoTask<T, TResult>(
            string taskDescription,
            Func<T, Task<TResult>> task,
            T arg)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            return await InternalDoTaskFunc(taskDescription, () => task(arg));
        }

        public static async Task<TResult> DoTask<T1, T2, TResult>(
            string taskDescription,
            Func<T1, T2, Task<TResult>> task,
            T1 arg1,
            T2 arg2)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            return await InternalDoTaskFunc(taskDescription, () => task(arg));
        }

         * */

        private static async Task InternalDoTaskAction(
            string taskDescription,
            Func<Task> task)
        {
            if (string.IsNullOrWhiteSpace(taskDescription))
            {
                throw new ArgumentNullException("taskDescription");
            }

            Splat.LogHost.Default.Info("Starting Task: " + taskDescription);

            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            await DoDebuggableTaskBlock(task());

            Splat.LogHost.Default.Info("Finished Task: " + taskDescription);
        }

        private static async Task<TResult> InternalDoTaskFunc<TResult>(
            string taskDescription,
            Func<Task<TResult>> task)
        {
            if (string.IsNullOrWhiteSpace(taskDescription))
            {
                throw new ArgumentNullException("taskDescription");
            }

            Splat.LogHost.Default.Info("Starting Task: " + taskDescription);

            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            var result = await DoDebuggableTaskBlock(task());

            Splat.LogHost.Default.Info("Finished Task: " + taskDescription);

            return result;
        }

        public static async Task DoDebuggableTaskBlock(Task task)
        {
            if (Debugger.IsAttached)
            {
                await task;
            }
            else
            {
                try
                {
                    await task;
                }
                catch (Exception)
                {

                    throw;
                }
            }
        }

        public static async Task<TResult> DoDebuggableTaskBlock<TResult>(Task<TResult> task)
        {
            if (Debugger.IsAttached)
            {
                return await task;
            }

            try
            {
                return await task;
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction(
            Func<string> taskDescription,
            Func<System.Threading.Tasks.Task> task)
        {
            await InternalDoTaskAction(taskDescription(), task);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T">The type of the argument</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T>(
            Func<T, string> taskDescription,
            Func<T, System.Threading.Tasks.Task> task,
            T arg)
        {
            await InternalDoTaskAction(taskDescription(arg), () => task(arg));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2>(
            Func<T1, T2, string> taskDescription,
            Func<T1, T2, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2),
                () => task(arg1, arg2));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3>(
            Func<T1, T2, T3, string> taskDescription,
            Func<T1, T2, T3, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3),
                () => task(arg1, arg2, arg3));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4>(
            Func<T1, T2, T3, T4, string> taskDescription,
            Func<T1, T2, T3, T4, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4),
                () => task(arg1, arg2, arg3, arg4));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5>(
            Func<T1, T2, T3, T4, T5, string> taskDescription,
            Func<T1, T2, T3, T4, T5, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5),
                () => task(arg1, arg2, arg3, arg4, arg5));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6>(
            Func<T1, T2, T3, T4, T5, T6, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7>(
            Func<T1, T2, T3, T4, T5, T6, T7, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10"></typeparam>
        /// <typeparam name="T11"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="T13">The type of argument 13</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <param name="arg13"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12,
            T13 arg13)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="T13">The type of argument 13</typeparam>
        /// <typeparam name="T14">The type of argument 14</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <param name="arg13"></param>
        /// <param name="arg14"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12,
            T13 arg13,
            T14 arg14)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="T13">The type of argument 13</typeparam>
        /// <typeparam name="T14">The type of argument 14</typeparam>
        /// <typeparam name="T15">The type of argument 15</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <param name="arg13"></param>
        /// <param name="arg14"></param>
        /// <param name="arg15"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12,
            T13 arg13,
            T14 arg14,
            T15 arg15)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="T13">The type of argument 13</typeparam>
        /// <typeparam name="T14">The type of argument 14</typeparam>
        /// <typeparam name="T15">The type of argument 15</typeparam>
        /// <typeparam name="T16">The type of argument 16</typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <param name="arg13"></param>
        /// <param name="arg14"></param>
        /// <param name="arg15"></param>
        /// <param name="arg16"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task TaskAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, System.Threading.Tasks.Task> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12,
            T13 arg13,
            T14 arg14,
            T15 arg15,
            T16 arg16)
        {
            await InternalDoTaskAction(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<TResult>(
            Func<string> taskDescription,
            Func<System.Threading.Tasks.Task<TResult>> task)
        {
            return await InternalDoTaskFunc(taskDescription(), task);
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T">The type of the argument</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T, TResult>(
            Func<T, string> taskDescription,
            Func<T, System.Threading.Tasks.Task<TResult>> task,
            T arg)
        {
            return await InternalDoTaskFunc(taskDescription(arg), () => task(arg));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, TResult>(
            Func<T1, T2, string> taskDescription,
            Func<T1, T2, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2),
                () => task(arg1, arg2));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, TResult>(
            Func<T1, T2, T3, string> taskDescription,
            Func<T1, T2, T3, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3),
                () => task(arg1, arg2, arg3));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <returns></returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, TResult>(
            Func<T1, T2, T3, T4, string> taskDescription,
            Func<T1, T2, T3, T4, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4),
                () => task(arg1, arg2, arg3, arg4));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, TResult>(
            Func<T1, T2, T3, T4, T5, string> taskDescription,
            Func<T1, T2, T3, T4, T5, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5),
                () => task(arg1, arg2, arg3, arg4, arg5));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, TResult>(
            Func<T1, T2, T3, T4, T5, T6, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="T13">The type of argument 13</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <param name="arg13"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12,
            T13 arg13)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="T13">The type of argument 13</typeparam>
        /// <typeparam name="T14">The type of argument 14</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <param name="arg13"></param>
        /// <param name="arg14"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12,
            T13 arg13,
            T14 arg14)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="T13">The type of argument 13</typeparam>
        /// <typeparam name="T14">The type of argument 14</typeparam>
        /// <typeparam name="T15">The type of argument 15</typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1"></param>
        /// <param name="arg2"></param>
        /// <param name="arg3"></param>
        /// <param name="arg4"></param>
        /// <param name="arg5"></param>
        /// <param name="arg6"></param>
        /// <param name="arg7"></param>
        /// <param name="arg8"></param>
        /// <param name="arg9"></param>
        /// <param name="arg10"></param>
        /// <param name="arg11"></param>
        /// <param name="arg12"></param>
        /// <param name="arg13"></param>
        /// <param name="arg14"></param>
        /// <param name="arg15"></param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12,
            T13 arg13,
            T14 arg14,
            T15 arg15)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15));
        }

        /// <summary>
        /// Asynchrously executes a Task that returns a result
        /// </summary>
        /// <typeparam name="T1">The type of argument 1</typeparam>
        /// <typeparam name="T2">The type of argument 2</typeparam>
        /// <typeparam name="T3">The type of argument 3</typeparam>
        /// <typeparam name="T4">The type of argument 4</typeparam>
        /// <typeparam name="T5">The type of argument 5</typeparam>
        /// <typeparam name="T6">The type of argument 6</typeparam>
        /// <typeparam name="T7">The type of argument 7</typeparam>
        /// <typeparam name="T8">The type of argument 8</typeparam>
        /// <typeparam name="T9">The type of argument 9</typeparam>
        /// <typeparam name="T10">The type of argument 10</typeparam>
        /// <typeparam name="T11">The type of argument 11</typeparam>
        /// <typeparam name="T12">The type of argument 12</typeparam>
        /// <typeparam name="T13">The type of argument 13</typeparam>
        /// <typeparam name="T14">The type of argument 14</typeparam>
        /// <typeparam name="T15">The type of argument 15</typeparam>
        /// <typeparam name="T16">The type of argument 16</typeparam>
        /// <typeparam name="TResult">
        /// The type of the return value of the method that this delegate encapsulates.This
        /// type parameter is covariant. That is, you can use either the type you specified
        /// or any type that is more derived. For more information about covariance and
        /// contravariance, see Covariance and Contravariance in Generics.
        /// </typeparam>
        /// <param name="taskDescription"></param>
        /// <param name="task"></param>
        /// <param name="arg1">The first parameter of the method that this delegate encapsulates</param>
        /// <param name="arg2">The second parameter of the method that this delegate encapsulates</param>
        /// <param name="arg3">The third parameter of the method that this delegate encapsulates</param>
        /// <param name="arg4">The fourth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg5">The fifth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg6">The sixth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg7">The seventh parameter of the method that this delegate encapsulates</param>
        /// <param name="arg8">The eight parameter of the method that this delegate encapsulates</param>
        /// <param name="arg9">The ninth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg10">The tenth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg11">The eleventh parameter of the method that this delegate encapsulates</param>
        /// <param name="arg12">The twelth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg13">The thirteenth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg14">The fourteenth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg15">The fifteenth parameter of the method that this delegate encapsulates</param>
        /// <param name="arg16">The sixteenth parameter of the method that this delegate encapsulates</param>
        /// <returns>The result of the task</returns>
        public static async System.Threading.Tasks.Task<TResult> TaskFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, string> taskDescription,
            Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, System.Threading.Tasks.Task<TResult>> task,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4,
            T5 arg5,
            T6 arg6,
            T7 arg7,
            T8 arg8,
            T9 arg9,
            T10 arg10,
            T11 arg11,
            T12 arg12,
            T13 arg13,
            T14 arg14,
            T15 arg15,
            T16 arg16)
        {
            return await InternalDoTaskFunc(
                taskDescription(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16),
                () => task(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16));
        }
    }
}